/*******************************************************************************
  * 文件：BoardCommC7_Comm.c
  * 作者：djy
  * 版本：v1.0.0
  * 日期：2019-05-15
  * 说明: 显示板与电源板C7通信协议，C7协议为海尔内部协议
*******************************************************************************/
#include "BoardCommC7_Comm.h"
#include "BoardCommC7_Dispatch.h"
#include "Serial.h"
#include "CRC.h"
#include "ComFun.h"
#include "main.h"
#include <math.h>
#include "RelayCtrl.h"
#include "RelayPower.h"
#include "SensorCtrl.h"
#include "MotorCtrl.h"
#include "Hardware_IO.h"
#include "OxygenSensor.h"

static BoardCommCtrl_ts sBoardCommCtrl;
/*******************************************************************************
  * 函数名: BoardCommFrameCheck
  * 功  能  ：底板通讯接收报文校验
  * 参  数 ：U8 au8Data[]：待校验的数据
  *         U8 u8len：数据长度
  * 返回值：NULL:非法报文
  *         BoardFrame_ts *：合法报文地址
  * 说  明 ：无
*******************************************************************************/
static BoardFrame_ts* BoardCommFrameCheck(U8 au8Data[],U8 u8len)
{
    U8 u8Index;

    // 遍历所有数据
    for(u8Index = 0;u8Index < u8len;u8Index++)
    { 
        // 寻找帧头
        if(au8Data[u8Index] == u8BOARD_COMM_C7_FRAME_STX 
            && au8Data[u8Index+1] == u8BOARD_COMM_C7_FRAME_STX)
        {
            // 指针转换
            BoardFrame_ts *psFrame = (BoardFrame_ts *)(au8Data+u8Index);

            // 剩余数据量不足以组成最短的报文
            if((u8len - u8Index) < 12)
            {
                // 返回NULL
                return NULL;
            }
            
            // 目的地址不对
            if(u16BOARD_COMM_C7_FRAME_POWER_ADDR != Get_BigEndian_Value(psFrame->au8DestAddr,3))
            {
                // 继续遍历
                continue;
            }

            // 源地址不对
            if(u16BOARD_COMM_C7_FRAME_DISPLAY_ADDR != Get_BigEndian_Value(psFrame->au8SourceAddr,3))
            {
                // 继续遍历
                continue;
            }

            // CRC8校验不通过
            if(psFrame->au8Data[psFrame->u8Len-9] != CRC_CalcCRC8(&(psFrame->u8Len),psFrame->u8Len,0))
            {
                // 继续遍历
                continue;
            }

            // 校验通过，返回合法报文指针
            return psFrame;
        }
    }

    // 遍历完所有数据，仍未找到合法报文
    return NULL;
}

/*******************************************************************************
  * 函数名: BoardCommRecvFrameTask
  * 功  能  ：底板通讯接收报文解析任务
  * 参  数 ：无
  * 返回值：无
  * 说  明 ：无
*******************************************************************************/
static void BoardCommRecvFrameTask(void)
{
    U8 au8RecvData[50];

    // 清空缓冲区
    memset(au8RecvData,0x00,sizeof(au8RecvData));
    // 将数据从串口接收缓冲区取出
    U8 u8RecvLen = SerialRxFIFOPeek(SERIAL_BOARD_COMM_CHN,au8RecvData,sizeof(au8RecvData));

    if(u8RecvLen != 0)
    {
        // 报文合法性校验
        BoardFrame_ts* psFrame = BoardCommFrameCheck(au8RecvData,u8RecvLen);

        if(psFrame != NULL)
        {
            // 合法报文处理
            U8 u8FrameLen = BoardCommFrame_Dispatch(psFrame);

            // 清空处理过的数据
            SerialRxFIFOClear(SERIAL_BOARD_COMM_CHN,u8FrameLen + ((U16)psFrame - (U16)au8RecvData));
        }
        else
        {
            // 非法报文且缓冲区数据长度超过50个字节
            if(u8RecvLen >= 50)
            {
                // 清空串口接收缓冲区，防止数据堆积
                SerialRxFIFOClear(SERIAL_BOARD_COMM_CHN,u8RecvLen);
            }
        }
    }
}

/*******************************************************************************
  * 函数名: BoardCommSendStateFrame
  * 功  能  ：底板通讯发送电源板状态报文
  * 参  数 ：无
  * 返回值：无
  * 说  明 ：无
*******************************************************************************/
static void BoardCommSendStateFrame(void)
{
    U8	au8SendBuff[53]; 	// 发送报文缓冲区
    BoardFrame_ts *psSendFrame = (BoardFrame_ts *)au8SendBuff;
    BoardCommSendData_ts *psSendData = (BoardCommSendData_ts *)psSendFrame->au8Data;

	// 组发送报文
    memset(au8SendBuff,0x00,sizeof(au8SendBuff));
    psSendFrame->u8STX1 = u8BOARD_COMM_C7_FRAME_STX;
    psSendFrame->u8STX2 = u8BOARD_COMM_C7_FRAME_STX;
    psSendFrame->u8Len  = sizeof(au8SendBuff) - 3;
    Put_BigEndian_Val(u16BOARD_COMM_C7_FRAME_DISPLAY_ADDR,psSendFrame->au8DestAddr,3);
    Put_BigEndian_Val(u16BOARD_COMM_C7_FRAME_POWER_ADDR,psSendFrame->au8SourceAddr,3);
	psSendFrame->u8Cmd_H = u16BOARD_COMM_C7_UPWARD >> 8;
	psSendFrame->u8Cmd_L = u16BOARD_COMM_C7_DOWNWARD;

	// 填充数据域
    psSendData->u8MajorVersion = U8_SW_MAJOR_VER;
    psSendData->u8MinorVersion = U8_SW_MINOR_VER;
    psSendData->u8RevisionVersion = U8_SW_REVISIOM_VER;
    psSendData->u8HardwareType = U8_HW_MAJOR_VER;

    // 传感器数据
	U16 u16CavitySensorVal = Sensor_GetCavitySensorVal(); 	// 箱体传感器数据
	U16 u16SteamGeneratorSensorVal = Sensor_GetSteamGeneratorSensorVal(); // 蒸汽发生器传感器数据
	U16 u16BottomSensorVal = Sensor_GetBottomSensorVal(); 	// 底部传感器数据
	U16 u16ProbeSensorVal  = Sensor_GetProbeSensorVal();	// 肉感探针数据
	U16 u16OxygenSensorVal = Sensor_GetOxygenSensorVal(); 	// 氧传感器数据

	// 数据传送
	psSendData->u8CavitySensor_H = u16CavitySensorVal >> 8;
	psSendData->u8CavitySensor_L = u16CavitySensorVal & 0xFF;
	psSendData->u8SteamGeneratorSensor_H = u16SteamGeneratorSensorVal >> 8;
	psSendData->u8SteamGeneratorSensor_L = u16SteamGeneratorSensorVal & 0xFF;
	psSendData->u8BottomSensor_H = u16BottomSensorVal >> 8;
	psSendData->u8BottomSensor_L = u16BottomSensorVal & 0xFF;
	psSendData->u8ProbeSensor1_H = u16ProbeSensorVal >> 8;
	psSendData->u8ProbeSensor1_L = u16ProbeSensorVal & 0xFF;
	psSendData->u8OxygenValH     = u16OxygenSensorVal >> 8;
	psSendData->u8OxygenValL     = u16OxygenSensorVal & 0xFF;
		
	// 负载状态
	psSendData->bUpOutHeatTubeStatus = RelayGetUpOutHeatTubeState();
	psSendData->bUpInHeatTubeStatus  = RelayGetUpInHeatTubeState();
	psSendData->bDownHeatTubeStatus  = RelayGetDownHeatTubeState();
	psSendData->bBackHeatTubeStatus  = RelayGetBackHeatTubeState();
	psSendData->bSteamPanStatus      = 0;
	psSendData->bOutsideSteamPanStatus = RelayGetSteamPanOutState();
	psSendData->bInsideSteamPanStatus = RelayGetSteamPanInState();
	psSendData->bConvectFanStatus     = RelayGetBackFan1State();
	psSendData->bCoolFan1Status		  = RelayGetCoolFan1State();  
	psSendData->bCoolFan2Status		  = RelayGetCoolFan2State(); 
	psSendData->bDoorLockStatus		  = 0;
	psSendData->bForkMotorStatus	  = 0;
	psSendData->bWaxMotorStatus		  = RelayGetMotorState();
	psSendData->bLampStatus		      = RelayGetLampState();
	psSendData->bZeroLine1Status	  = RelayGetZeroLine1State();
	psSendData->bZeroLine2Status	  = RelayGetZeroLine2State();
	psSendData->bIntakePumpStatus	  = Hardware_GetInletValveState();
	psSendData->bDrainPumpStatus	  = Hardware_GetOutletValveState();
	psSendData->bZeroLine3Status	  = 0;
	psSendData->bOxygenPositionStatus = OxygenSensorIsWork();
	psSendData->bOxygenWorkStatus     = OxygenSensorIsWork();
	psSendData->bDoorStatus			  = Hardware_DoorStateCheck();
	psSendData->bWasteWaterStatus	  = Hardware_WasteWaterFullCheck();
	psSendData->bMotorUpStatus		  = Hardware_OpenStopCheck();
	psSendData->bMotorDownStatus	  = Hardware_CloseStopCheck();
	psSendData->WasteWaterPosStatus   = Hardware_WasteWaterBoxCheck();
	psSendData->bWaterBoxStatus		  = Hardware_LeftWaterPosCheck();
	psSendData->bWaterBoxEmptyStatus  = Hardware_CleanWaterLackCheck();
	psSendData->bSteamPanWaterStatus  = Hardware_SteamWaterPosCheck();
	psSendData->u2CavitySensor1Err	  = Sensor_GetCavitySensorErr();
	psSendData->u2SteamPanSensorErr   = Sensor_GetSteamGeneratorSensorErr();
	psSendData->u2BottomSensorErr     = Sensor_GetBottomSensorErr();
	psSendData->u2Probe1Sensor1Err	  = Sensor_GetProbeSensorErr();

	if(eMOTOR_FORWARD == Motor_GetState())
	{
        // 正转中
		psSendData->bLiftingMotorStatus = 1;
	}
	else if(eMOTOR_REVERSE == Motor_GetState())
	{
        // 反转中
		psSendData->bLiftingMotorStatus = 2;
	}
	else
	{
        // 电机停止
		psSendData->bLiftingMotorStatus = 0;
	}

	// 校验
	psSendData->u8CRC = CRC8(&(psSendFrame->u8Len),50);
	
	// 增加冗余字符
	U8 u8Index;
	U8 u8STX = u8BOARD_COMM_C7_FRAME_SURPLUS;

	// 按字节发送报文
	for(u8Index = 0;u8Index < sizeof(au8SendBuff);u8Index++)
	{
		// 发送报文数据
		SerialSendData(SERIAL_BOARD_COMM_CHN,au8SendBuff+u8Index,1);
		
		if(u8Index >= 2 && au8SendBuff[u8Index] == u8BOARD_COMM_C7_FRAME_STX)
		{
			// 增加冗余字节
			SerialSendData(SERIAL_BOARD_COMM_CHN,&u8STX,1);
		}
	}
}

/*******************************************************************************
  * 函数名: BoardCommTimingSendHook_100MS
  * 功  能  ：底板通讯定时发送任务
  * 参  数 ：无
  * 返回值：无
  * 说  明 ：100ms定时发送电源板状态
*******************************************************************************/
static void BoardCommTimingSendHook_100MS(void)
{
    // 发送电源板状态
    BoardCommSendStateFrame();
}

/*******************************************************************************
  * 函数名: BoardComm_Init
  * 功  能  ：底板通讯C7协议初始化
  * 参  数 ：无
  * 返回值：无
  * 说  明 ：无
*******************************************************************************/
void BoardComm_Init(void)
{
    // 创建解析任务
    OS_TaskCreate(BoardCommRecvFrameTask);
    // 启动发送定时器
    OS_TimerStart(&(sBoardCommCtrl.sTimer),
                  100,
                  BoardCommTimingSendHook_100MS);
}

